﻿using ApprovalTests;
using ApprovalTests.Reporters;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace DZParallelLib.Test
{
    [TestClass]
    public class RenderDZCollectionImageTest
    {
        [TestInitialize]
        public void TestInit()
        {
            UtilsForTest.SetupTest();
        }

        [TestMethod]
        public void TestCTor()
        {
            var r = new RenderDZCollectionImage();
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public async Task TestRenderBadFile()
        {
            var r = new RenderDZCollectionImage();
            await r.RenderImage(new FileInfo("bogus.xml"), new DirectoryInfo(@".\dzout"));
        }

        [TestMethod]
        [DeploymentItem("DZImage1", "DZImage1")]
        [UseReporter(typeof(TortoiseImageDiffReporter), typeof(ClipboardReporter))]
        public void TestRendering1ImageFileLevel8()
        {
            var r = new RenderDZCollectionImage();
            r.RenderImage(new FileInfo(@"DZImage1\dz.xml"), new DirectoryInfo(@".\dzout")).Wait();
            var img = new FileInfo(@".\dzout\8\0_0.png");
            Approvals.Verify(img);
        }

        [TestMethod]
        [DeploymentItem("DZImageSmall", "DZImageSmall")]
        [UseReporter(typeof(TortoiseImageDiffReporter), typeof(ClipboardReporter))]
        public void TestRenderingSmallImage()
        {
            var r = new RenderDZCollectionImage();
            r.RenderImage(new FileInfo(@"DZImageSmall\dz.xml"), new DirectoryInfo(@".\dzout")).Wait();
            var img = new FileInfo(@".\dzout\8\0_0.png");
            Approvals.Verify(img);
        }

        [TestMethod]
        [DeploymentItem("DZImage2", "DZImage2")]
        public async Task RenderTwoImages()
        {
            var r = new RenderDZCollectionImage();
            await r.RenderImage(new FileInfo(@"DZImage2\dz.xml"), new DirectoryInfo(@".\dzout"));
            Assert.AreEqual(2, Directory.EnumerateFiles(@".\dzout\8").Count(), "# of final images written");
        }

        [TestMethod]
        [DeploymentItem("DZImage1", "DZImage1")]
        [UseReporter(typeof(TortoiseImageDiffReporter), typeof(ClipboardReporter))]
        public void TestRendering1ImageFileLevel6()
        {
            var r = new RenderDZCollectionImage();
            r.RenderImage(new FileInfo(@"DZImage1\dz.xml"), new DirectoryInfo(@".\dzout")).Wait();
            var img = new FileInfo(@".\dzout\6\0_0.png");
            Approvals.Verify(img);
        }

        [TestMethod]
        [DeploymentItem("DZImage2", "DZImage2")]
        [UseReporter(typeof(TortoiseImageDiffReporter), typeof(ClipboardReporter))]
        public async Task Render2ImagesButOneRedone()
        {
            var r = new RenderDZCollectionImage();
            await r.RenderImage(new FileInfo(@"DZImage2\dz.xml"), new DirectoryInfo(@".\dzout"));
            var outDir = new DirectoryInfo(@".\dzout\8");
            foreach (var f in outDir.EnumerateFiles())
            {
                f.Delete();
            }
            await r.RenderImage(new FileInfo(@"DZImage2\dz.xml"), new DirectoryInfo(@".\dzout"), new HashSet<ulong>() { 1 });
            Assert.AreEqual(1, outDir.EnumerateFiles().Count(), "# of re-rendered files");
        }

        [TestMethod]
        public void TestSimpleMortonNumber()
        {
            var r = new RenderDZCollectionImage();
            var mv = r.CalculateImageCRLocation(0);
            Assert.AreEqual(Tuple.Create<ulong, ulong>(0, 0), mv, "0");

            mv = r.CalculateImageCRLocation(1);
            Assert.AreEqual(Tuple.Create<ulong, ulong>(1, 0), mv, "1");

            mv = r.CalculateImageCRLocation(5);
            Assert.AreEqual(Tuple.Create<ulong, ulong>(3, 0), mv, "5");

            mv = r.CalculateImageCRLocation(10);
            Assert.AreEqual(Tuple.Create<ulong, ulong>(0, 3), mv, "10");
        }

        [TestMethod]
        [UseReporter(typeof(DiffReporter))]
        public void TestMortonUpTo10()
        {
            var r = new RenderDZCollectionImage();
            var mlist = Enumerable.Range(0, 20).Select(i => r.CalculateImageCRLocation((ulong)i));
            Approvals.Verify(mlist.AsString());
        }

        [TestMethod]
        public void TestSimpleTileLocations()
        {
            var r = new RenderDZCollectionImage();
            var t = r.CalculateTile(0, Tuple.Create<ulong, ulong>(0, 0));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(0, 0), t, "0,0");

            t = r.CalculateTile(8, Tuple.Create<ulong, ulong>(0, 0));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(0, 0), t, "0,0");

            t = r.CalculateTile(8, Tuple.Create<ulong, ulong>(5, 5));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(5, 5), t, "5,5");

            t = r.CalculateTile(4, Tuple.Create<ulong, ulong>(4, 4));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(0, 0), t, "2,2");

            t = r.CalculateTile(4, Tuple.Create<ulong, ulong>(5, 5));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(0, 0), t, "3,3");

            t = r.CalculateTile(7, Tuple.Create<ulong, ulong>(1, 1));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(0, 0), t, "1,1");

            t = r.CalculateTile(7, Tuple.Create<ulong, ulong>(2, 1));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(1, 0), t, "1,1");

            t = r.CalculateTile(8, Tuple.Create<ulong, ulong>(1, 0));
            Assert.AreEqual(Tuple.Create<ulong, ulong>(1, 0), t, "for level 8, at 1,0");
        }

        [TestMethod]
        public void TestLevelSize()
        {
            var r = new RenderDZCollectionImage();
            Assert.AreEqual((uint)1, r.CalculateLevelSize(0), "Level 0");
            Assert.AreEqual((uint)16, r.CalculateLevelSize(4), "Level 0");
            Assert.AreEqual((uint)1024, r.CalculateLevelSize(10), "Level 0");
        }

        [TestMethod]
        public void TestCalculateTilePixelOffset()
        {
            var r = new RenderDZCollectionImage();
            Assert.AreEqual(new Point(0, 0), r.CalculateTilePixelOffset(5, Tuple.Create<ulong, ulong>(0, 0)), "level 5, 0,0");
            Assert.AreEqual(new Point(500 - 256, 500 - 256), r.CalculateTilePixelOffset(0, Tuple.Create<ulong, ulong>(500, 500)), "level 0, 500, 500");
            Assert.AreEqual(new Point(0, 0), r.CalculateTilePixelOffset(8, Tuple.Create<ulong, ulong>(43, 1)), "level 8, 43, 1");
            Assert.AreEqual(new Point(128, 128), r.CalculateTilePixelOffset(7, Tuple.Create<ulong, ulong>(1, 1)), "level 7, 1, 1");
        }

        [TestMethod]
        public void TestCalculateImageScaling()
        {
            var r = new RenderDZCollectionImage();
            Assert.AreEqual(1.0, r.CalculateImageScaling(8, 256, 256), "level 8, 256, 256");
            Assert.AreEqual(0.5, r.CalculateImageScaling(7, 256, 128), "level 7, 256, 128");
        }
    }
}
